<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <title>预备知识</title>
</head>

<body>
  1、函数对象与实例对象
  <br><br>
  <script>
    // 函数对象：函数作为对象使用时，简称为函数对象。
    function Person (name, age) {
      this.name = name;
      this.age = age;
    }
    Person.a = 'boy';
    // console.log(Person.name); // Person.name 默认是构造函数名，无法自己定义
    // console.log(Person.a);  //'boy'

    // 实例对象：new 构造函数或类产生的对象，我们称之为实例对象。
    const p = new Person('张三', 18)
    // console.log(p.name)
    // console.log(p.age)
  </script>

  2、回调函数：- 你定义的函数，你没有调用，但最终它执行了(在某个时刻或某个条件下)
  <br><br>
  <script>
    /* （1）同步的回调函数：
      
          理解：立即在主线程上执行，不会放入回调队列中。
        
          举例：数组遍历相关的回调函数 / Promise 的 executor 函数。
      
       （2）异步的回调函数：
      
          理解：不会立即执行，会放入回调队列，等主线程的程序都执行完以后执行。
        
          举例：定时器回调 / ajax 回调 / Promise 的成功、失败的回调 / dom事件回调函数 / vue生命周期回调函数
    */

    // 同步回调演示，结果是输出 1 2 3 4 主线程代码执行
    /* const arr = [1, 2, 3, 4]
    arr.forEach((item) => { console.log(item); });
    console.log('主线程代码执行'); */

    // 异步回调演示，结果输出 主线程代码执行 定时器回调
    /* setTimeout(() => { console.log('定时器回调'); }, 0);
    console.log('主线程代码执行'); */
  </script>

  3、错误（Error）及其捕获和处理
  <br><br>
  <script>
    //#region 表示一个可以折叠的代码块
    /** 1.错误的类型
      Error           所有错误的父类型(控制台不会报出这个类型)
      ReferenceError  引用的变量不存在
      TypeError       变量或参数不属于有效类型
      SyntaxError     语法错误
      RangeError      数值变量或参数超出其有效范围 */
    
    // 演示ReferenceError  引用的变量不存在
    // console.log(a)  // Uncaught ReferenceError: a is not defined

    // 演示TypeError 变量或参数不属于有效类型
   /*  const fun = () => {}
    fun()() //Uncaught TypeError: fun(...) is not a function */

    // 演示SyntaxError  语法错误
    // console.log(; //Uncaught SyntaxError: Unexpected token ';'

    // 演示RangeError 数值变量或参数超出其有效范围 
    /* const fun = () => { fun() }
    fun() //Uncaught RangeError: Maximum call stack size exceeded */
    //#endregion

    /**2.错误处理
     * 2.1 捕获错误 try...catch语句标记要尝试的语句块，并指定一个出现异常时抛出的响应
     * try语句包含了由一个或者多个语句组成的try块，和至少一个catch块或者一个finally块的其中一个，
     * 或者两个兼有， 下面是三种形式的try声明：
     *  try...catch
     *  try...finally
     *  try...catch...finally
     * 
     * 2.2 抛出错误 throw expression; 
     * throw语句用来抛出一个用户自定义的异常。当前函数的执行将被停止（throw之后的语句将不会执行），
     * 并且控制将被传递到调用堆栈中的第一个catch块。如果调用者函数中没有catch块，程序将会终止。
     * 
    */

    // try中放可能会出错的代码，一旦出错立即停止try中的代码执行，调用catch，并携带错误信息
    /* try {
      console.log(1);
      console.log(a);
      console.log(2);
    } catch (error) {
      console.log('程序出错了--',error) //程序出错了-- ReferenceError: a is not defined
    } */

    // 抛出错误
    /* 3.错误对象
        message 属性：错误相关信息。
        stack 属性：记录信息。 */
    function demo() {
      const date = Date.now()
      if (date%2 === 0 ) {
        console.log('偶数，可以工作');
      }else{
        throw new Error('奇数，不可以工作') //一般抛出错误都是抛出一个Error实例对象
      }
    }

    try {
      demo()
    } catch (error) {
      console.log(error);   //直接打印error就是输出error.stack内容
      console.log(error.message);   //奇数，不可以工作
      console.log(error.stack);     //Error: 奇数，不可以工作 at demo(01 - 预备知识.html: 112: 15) at 01 - 预备知识.html: 117: 7
    }

  </script>
</body>

</html>